// user.go
package models

import (
	"crypto/tls"
	"encoding/json"
	"errors"
	"time"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/httplib"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
)

var (
	code2SessionUrlStart = "https://api.weixin.qq.com/sns/jscode2session?appid=wxa4dedfcf2df51494&secret=43cb423f76abc3b34a083b738416e4f3&js_code="
	code2SessionUrlEnd   = "&grant_type=authorization_code"
	wechatUrl            = "https://api.weixin.qq.com/sns/jscode2session?"
	appid                = "wxa4dedfcf2df51494"
	secret               = "43cb423f76abc3b34a083b738416e4f3"
)

type Manager struct {
	Id         int       `orm:"column(Id)"`
	Loginname  string    `orm:"column(Login)"`
	Password   string    `orm:"column(Pwd)"`
	Createtime time.Time `orm:"column(CreateTime)"`
	Active     string    `orm:"column(Active)"`
	Role       string    `orm:"column(Role)"` //admin,manager
}

func (m *Manager) TableName() string {
	return "Manager"
}

type User struct {
	Id         int       `orm:"column(Id)"`
	UnionId    string    `orm:"column(UnionId)"`
	OpenId     string    `orm:"column(OpenId)"`
	SessionKey string    `orm:"column(SessionKey)"`
	NickName   string    `orm:"column(NickName)"`
	HeadImg    string    `orm:"column(HeadImg)"`
	Timestamp  time.Time `orm:"column(CreateTime)"`
	Role       string    `orm:"column(Role)"`   //customer,staff,manager
	Status     string    `orm:"column(Status)"` // Active,unActive
	Tel        string    `orm:"column(Tel)"`
	Statff     *Statff   `orm:"null;rel(one);on_delete(set_null)"`
}

/*
func (u *User) TableName() string {
	return "User"
}
*/
type Statff struct {
	Id         int        `orm:"column(Id)"`
	NickName   string     `orm:"column(NickName)"`
	Imag       string     `orm:"column(Imag)"`
	Createtime time.Time  `orm:"column(CreateTime)"`
	Active     string     `orm:"column(Active)"`  //Active,unActive
	Role       int        `orm:"column(Role)"`    //1:店长，2:资深，3:学徒,0:Normal
	RoleDes    string     `orm:"column(RoleDes)"` //1:店长，2:资深，3:学徒,0:Normal
	Product    string     `orm:"column(Product)"` //服务内容 1，2，3，4，5
	StoreId    int        `orm:"column(StoreId)"`
	User       *User      `orm:"reverse(one)"`
	Store      *StoreInfo `orm:"rel(fk)"`
}

func (u *Statff) TableName() string {
	return "Statff"
}

type wxInfo struct {
	OpenId     string `json:"openid"`
	SessionKey string `josn:"session_key"`
	UnionId    string `json:"unionid"`
}

func AddUserByCode(code, nickName, icon string) (string, string, error) {
	u, err := getInfoFromWechat(code)
	if err != nil {
		beego.Error("get user info from weixin failed!\n")
		return "", "", err
	}

	newUser := User{
		UnionId:    u.UnionId,
		OpenId:     u.OpenId,
		SessionKey: u.SessionKey,
		NickName:   nickName,
		HeadImg:    icon,
		Timestamp:  time.Now(),
		Role:       "customer",
		Status:     "Active",
		Tel:        "",
	}

	o := orm.NewOrm()
	o.Using("default")

	// 三个返回参数依次为：是否新创建的，对象 Id 值，错误
	if created, id, err := o.ReadOrCreate(&newUser, "OpenId"); err == nil {

		if created {
			beego.Debug("New Insert an object. Id:", id)
		} else {

			if newUser.Statff != nil {
				err = o.Read(newUser.Statff)
				if err == nil && newUser.Statff.Id != 0 {
					newUser.Role = "staff"
				} else {
					beego.Debug("Get statff info: ", err)
				}
			}
			beego.Debug("Get an object. Id:", id)
		}
		ss, err := getSession(newUser.OpenId, newUser.UnionId)

		return ss, newUser.Role, err

	} else {
		beego.Error(err)
		return "", "", err
	}
}

func getInfoFromWechat(code string) (*wxInfo, error) {

	url := code2SessionUrlStart + code + code2SessionUrlEnd

	req := httplib.Get(url)

	req.SetTimeout(5*time.Second, 5*time.Second)
	req.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})

	result, err := req.Bytes()
	if err != nil {
		beego.Error("get user info failed!\n")
		return nil, err
	}

	var errWx errWxResult
	err = json.Unmarshal(result, &errWx)
	if nil != err {
		beego.Error("json decode failed!\n")
		return nil, err
	}

	if errWx.ErrCode != 0 {
		beego.Error("wx return failed!\n", errWx)
		return nil, errors.New(errWx.Msg)
	}

	var u wxInfo
	err = json.Unmarshal(result, &u)
	if nil != err {
		beego.Error("json decode failed!\n")
		return nil, err
	}

	return &u, nil
}

func GetUserByOpenId(openId string) (*User, error) {

	newUser := User{}

	o := orm.NewOrm()
	o.Using("default")

	qs := o.QueryTable(newUser)
	err := qs.Filter("OpenId", openId).One(&newUser)
	return &newUser, err
}

func UpdateUserInfo(userId int, nickname, icon string) error {

	newUser := User{
		Id:       userId,
		NickName: nickname,
		HeadImg:  icon,
	}

	o := orm.NewOrm()
	o.Using("default")

	_, err := o.Update(&newUser, "NickName", "HeadImg")
	if err != nil {
		beego.Error("update userInfo failed:", userId, err)
	}

	return err
}

func RegisterStaff(user *User, nickName, icon string, storeId int) error {

	o := orm.NewOrm()
	o.Using("default")

	store := StoreInfo{
		Id: storeId,
	}

	newStaff := Statff{
		NickName:   nickName,
		Imag:       icon,
		Active:     "unActive",
		StoreId:    storeId,
		Createtime: time.Now(),
		User:       user,
		Store:      &store,
	}

	_, err := o.Insert(&newStaff)
	if nil != err {
		beego.Error("insert staff failed!", err)
	}

	return err
}
